package com.xc.stock.domain.basic.repository;

import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

public class LocalCache<P, ID extends Serializable> {
	CacheBuilder<Object, Object> builder;
	LoadingCache<String, Map<ID, P>> _cache = null;
	Function<String, List<P>> fun;
	Function<P, ID> id;
	
	Function<String, List<P>> fun() {
		return fun;
	}
	Function<P, ID> id() {
		return id;
	}
	
	public LocalCache(Function<String, List<P>> fun, Function<P, ID> id) {
		this.builder = CacheBuilder.newBuilder().maximumSize(2000000).expireAfterWrite(2 * 60, TimeUnit.SECONDS);
		this.fun = fun;
		this.id = id;
	}
	
	public LocalCache(CacheBuilder<Object, Object> builder, Function<String, List<P>> fun, Function<P, ID> id) {
		this.builder = builder;
		this.fun = fun;
		this.id = id;
	}
	
	public List<P> cacheList() {
		return Lists.newArrayList(cacheMap().values());
	}
	
	public void cleanUp() {
		if(_cache != null) {
			_cache.cleanUp();
		}
	}
	
	public void invalidateAll() {
		if(_cache != null) {
			_cache.invalidateAll();
		}
	}

	public Map<ID, P> cacheMap() {
		if(_cache == null) {
			_cache = builder.build(CacheLoader.from(string -> {
            	List<P> list = fun().apply(string);
                Map<ID, P> map = list
                        .stream()
                        .collect(Collectors.toMap(val -> id().apply(val), val -> val));
                return map;
            }));
		}
		try {
            return _cache.get("UNI_KEY");
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        return Maps.newHashMap();
	}

	public P findCacheById(ID id) {
		return cacheMap().get(id);
	}
}
